﻿using System;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using Framework.Core;
using Framework.Remoting.Conventions;
using log4net;
using ProtoBuf.ServiceModel;

namespace Framework.Remoting.Hosting
{
    public class ServiceHostFactory : IServiceHostFactory<ServiceHost>
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof (ServiceHostFactory));

        public ServiceHostFactory(IWcfServiceInfoFactory wcfServiceInfoFactory)
        {
            WcfServiceInfoFactory = wcfServiceInfoFactory;
        }

        private IWcfServiceInfoFactory WcfServiceInfoFactory { get; set; }

        
        public virtual ServiceHost Create(Type serviceType, EnvMode envMode)
        {
            var contractType = serviceType.GetInterfaces().First(i => i.HasCustomAttribute<ServiceContractAttribute>());

            var wcfServiceInfo = WcfServiceInfoFactory.Create(envMode, contractType);

            var host = new ServiceHost(serviceType, wcfServiceInfo.Uri);

            var behaviors = host.AddServiceEndpoint(contractType, wcfServiceInfo.Binding, wcfServiceInfo.Uri).Behaviors;

            behaviors.Add(new ProtoEndpointBehavior());
            host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = false;

            host.Open();

            Logger.InfoFormat("Service : {0} hosted", wcfServiceInfo.Uri);

            OnHostOpened(contractType, serviceType, wcfServiceInfo.Uri);

            return host;
        }

        public virtual void Close(ServiceHost host)
        {
            host.Close();
            OnHostClosed(host.Description.Endpoints.First().Contract.ContractType);
        }

        protected virtual void OnHostOpened(Type contractType, Type serviceType, Uri baseAddress)
        {
        }

        protected virtual void OnHostClosed(Type contractType)
        {
        }
    }
}